package source.javadog.mysource;

import java.net.InetSocketAddress;
import java.util.Map;
import java.util.Properties;
import java.util.concurrent.Semaphore;
import java.util.concurrent.atomic.AtomicLong;
import java.util.logging.Logger;

import static source.javadog.mysource.MyDataSources.*;

/**
 * Author : manyu
 * Date: 2018/9/9 22:30
 * Description:
 */
public abstract class MyPoolSource<DBChannel> {

    protected final AtomicLong saveCounter = new AtomicLong();

    protected final AtomicLong usingCounter = new AtomicLong();

    protected final Logger logger;

    protected String url;

    protected InetSocketAddress servaddr;

    protected String username;

    protected String password;

    protected String database;

    protected String encoding;

    protected final Semaphore semaphore;

    protected final AtomicLong creatCounter = new AtomicLong();

    protected final AtomicLong cycleCounter = new AtomicLong();

    protected Map<String,String> dbMap;

    protected final String dbtype;

    protected Properties attributes = new Properties();

    protected final int maxconns;

    public MyPoolSource(Semaphore semaphore, Map<String, String> dbMap, Logger logger) {
        this.logger = logger;
        this.dbMap = dbMap;
        this.url = dbMap.get(JDBC_URL);
        this.username = dbMap.get(JDBC_USER);
        this.password = dbMap.get(JDBC_PWD);
        this.semaphore = semaphore;
        this.encoding = dbMap.getOrDefault(JDBC_ENCODING, "");
        this.maxconns = Math.max(8, Integer.decode(dbMap.getOrDefault(JDBC_CONNECTIONS_LIMIT, "" + Runtime.getRuntime().availableProcessors() * 100)));
        String dbtype0 = "";
        { //jdbc:mysql:// jdbc:microsoft:sqlserver:// 取://之前的到最后一个:之间的字符串
            int pos = this.url.indexOf("://");
            if (pos > 0) {
                String url0 = this.url.substring(0, pos);
                pos = url0.lastIndexOf(':');
                if (pos > 0) dbtype0 = url0.substring(pos + 1);
            } else { //jdbc:oracle:thin:@localhost:1521
                String url0 = url.substring(url.indexOf(":") + 1);
                pos = url0.indexOf(':');
                if (pos > 0) dbtype0 = url0.substring(0, pos);
            }
            if ("mysqlx".equalsIgnoreCase(dbtype0)) dbtype0 = "mysql"; //MySQL X DevAPI
        }
        this.dbtype = dbtype0.toLowerCase();
        parseAddressAndDbnameAndAttrs();

        if ("mysql".equals(this.dbtype)) {
            if (this.encoding.isEmpty()) this.encoding = attributes.getProperty("characterEncoding", "");
        }

    }

    protected void parseAddressAndDbnameAndAttrs() {
        String url0 = this.url.substring(this.url.indexOf("://") + 3);
        int pos = url0.indexOf('?'); //127.0.0.1:5432/db?charset=utr8&xxx=yy
        if (pos > 0) {
            String params = url0.substring(pos + 1).replace("&amp;", "&");
            for (String param : params.split("&")) {
                int p = param.indexOf('=');
                if (p < 1) continue;
                this.attributes.put(param.substring(0, p), param.substring(p + 1));
            }
            url0 = url0.substring(0, pos);
        }
        pos = url0.indexOf('/'); //127.0.0.1:5432/db
        if (pos > 0) {
            this.database = url0.substring(pos + 1);
            url0 = url0.substring(0, pos);
        }
        pos = url0.indexOf(':');
        if (pos > 0) {
            this.servaddr = new InetSocketAddress(url0.substring(0, pos), Integer.parseInt(url0.substring(pos + 1)));
        } else {
            this.servaddr = new InetSocketAddress(url0, getDefaultPort());
        }
    }

    protected abstract int getDefaultPort();

    public abstract DBChannel poll();

    public final String getDbtype() {
        return dbtype;
    }

    public abstract void offerConnection(DBChannel conn);
}
